// Bachelor of Software Engineering 
// Media Design School 
// Auckland
// New Zealand
// 
// (c) 2005 - 2014 Media Design School 
// 
// File Name : Foundation.cpp
// Description : Foundation implementation
// Author : Serge Radinovich
// Mail : srad015@hotmail.com

#include "Foundation.h"
#include "Game.h"

///////////////////////
//Default constructor
//Sets up the 4 piles of the Foundation
//Also sets up the null spaces
//////////////////////
Foundation::Foundation(void)
{
	//Add four piles (lists) to the Foundation
	for(int i = 0; i < 4; i++)
	{
		this->m_Stacks.push_back(new std::list<Card*>);
	}

	for(int i = 0; i < 4; i++)
	{
		m_NullSpaces.push_back(GameObject(static_cast<float>(s_s_kiLeft + i*s_kiDistBetweenPiles), static_cast<float>(s_s_kiTop), Card::s_kiWidth, Card::s_kiHeight));
	}
}

///////////////////////
//Destructor
//Destruction is done in CardPileGroup.cpp
//////////////////////
Foundation::~Foundation(void)
{
}

///////////////////////
//Renders all cards in Foundation
// Only draws the top card or a null space
//////////////////////
void Foundation::Draw()
{
	for(int pile = 0; pile < 4; pile++)
	{
		if(!m_Stacks[pile]->empty())
		{
			//Draw all cards in piles	
			for(auto card = m_Stacks[pile]->begin(); card != m_Stacks[pile]->end(); card++)
			{
				(*card)->Draw();
			}
		}
		else
		{
			//Draw nullspace if pile is empty
			Game* _pGame = Game::GetGameInstance();
			BitBlt(_pGame->GetBackBuffer()->getDC(), s_s_kiLeft + pile*s_kiDistBetweenPiles, s_s_kiTop, Card::s_kiWidth, Card::s_kiHeight, m_hNullSpaceDC, 0, 0, SRCAND);
		}
	}
}

///////////////////////
//Overloaded pure virtual function from base class
//Returns a pointer to a list of cards grabbed from foundation
//The foundation can only ever return 1 card in the list because of the game rules
//////////////////////
std::list<Card*>* Foundation::AttemptCardGrab(Vector2 _clickPos, std::list<Card*>* _pGrabbedCards)
{
	//Error check: player should not be moving cards around already
	if(_pGrabbedCards->empty())
	{	
		for(int pile = 0; pile < static_cast<int>(m_Stacks.size()); pile++)
		{
			//Cannot grab cards from an empty pile
			if(m_Stacks[pile]->empty())
			{
				continue;
			}
			//Check whether mouse pointer collided with piles of cards from Foundation
			if(CheckCollision(_clickPos, m_Stacks[pile]->back()))
			{
				//Add cards to working list
				_pGrabbedCards->push_back(m_Stacks[pile]->back());
				m_Stacks[pile]->pop_back();
				return m_Stacks[pile];
			}
		}
	}	
	return nullptr;
}


///////////////////////
//Overloaded pure virtual function from base class
//Checks for collision between mouse pointer and Foundation piles
//Returns true if card can be deposited into foundation pile based on game rules
//////////////////////
bool Foundation::AttemptCardDeposit(Vector2 _clickPos, std::list<Card*>* _pGrabbedCards,  std::list<Card*>* &_pListDepositedTo)
{
	//Can only ever deposit 1 card at a time to the Foundation
	if (_pGrabbedCards->size() == 1)
	//Receive cards
	{
		for(int i = 0; i < static_cast<int>(m_NullSpaces.size()); i++)
		{
			//Find collision with one of the Foundation Piles
			if(CheckCollision(&m_NullSpaces[i], _pGrabbedCards->front()))
			{
				//Make sure the card can be deposited according to game rules
				if(ValidCardDeposit(_pGrabbedCards->front(), i))
				{
					//Animate the transition
					CardPileGroup::Animate(_pGrabbedCards, m_NullSpaces[i].GetPos());
					//Transfer the cards
					m_Stacks[i]->push_back(_pGrabbedCards->front());
					_pGrabbedCards->pop_front();
					ArrangeCardPositions(); 
					//Return list deposited to
					_pListDepositedTo = m_Stacks[i];
					return true;
				}
				else
				{
					return false;
				}
			}
		}
	}
	return false;
}

///////////////////////
//Returns true if card can be deposited into foundation pile based on game rules
//////////////////////
bool Foundation::ValidCardDeposit(const Card* const _pCard, const int _iPile) const
{
	//For debugging!
	//return true;//THIS INVALIDATES RULES

	//Can only deposit an ace to an empty Foundation pile
	if(m_Stacks[_iPile]->empty())
	{
		if(_pCard->GetRank() == ACE)
		{
			return true;
		}
		else
		{
			return false;
		}
	}
	else
	{
		//Can only deposit same suit and rank higher than top card in Foundation pile
		Card* _pTopCard = 	m_Stacks[_iPile]->back();
		if(_pTopCard->GetSuit() == _pCard->GetSuit() && _pTopCard->GetRank() == _pCard->GetRank() - 1)
		{
			return true;
		}
	}
	return false;
}

///////////////////////
//Sets all positions of cards in a particular pile
//////////////////////
void Foundation::ArrangeCardPositions()
{
	for(int pile = 0; pile < static_cast<int>(m_Stacks.size()); pile++)
	{
		//Do not change positions of empty piles
		if(m_Stacks[pile]->empty())
		{
			continue;
		}
		//Set the positions to nullspaces for Foundation piles
		for(auto card = m_Stacks[pile]->begin(); card != m_Stacks[pile]->end(); card++)
		{
			(*card)->SetPos(m_NullSpaces[pile].GetPos().x, m_NullSpaces[pile].GetPos().y);
		}
	}
}

///////////////////////
//Undoes a move done in relation to the 
//////////////////////
void Foundation::UndoMove(Move* _move)
{
	while(!_move->m_pCardsMoved->empty())
	{
		_move->m_pPileMovedFrom->push_back(_move->m_pCardsMoved->back());
		_move->m_pCardsMoved->pop_back();
	}
	
	return;

}

///////////////////////
//Returns true if the game winning condition is met
//////////////////////
bool Foundation::GameWon()
{
	int _iCardCount = 0;

	for(int pile = 0; pile < static_cast<int>(m_Stacks.size()); pile++)
	{
		_iCardCount += m_Stacks[pile]->size();
	}
	//All cards must be in the Foundation
	if(_iCardCount == 52)
	{
		return true;
	}
	else
	{
		return false;
	}
}